﻿namespace MoPhoGames.USpeak.Codec
{
    using MoPhoGames.USpeak.Core.Utils;
    using NSpeex;
    using System;

    public class SpeexCodec : ICodec
    {
        private SpeexDecoder m_narrow_dec = new SpeexDecoder(NSpeex.BandMode.Narrow, true);
        private SpeexEncoder m_narrow_enc = new SpeexEncoder(NSpeex.BandMode.Narrow);
        private SpeexDecoder m_ultrawide_dec = new SpeexDecoder(NSpeex.BandMode.UltraWide, true);
        private SpeexEncoder m_ultrawide_enc = new SpeexEncoder(NSpeex.BandMode.UltraWide);
        private SpeexDecoder m_wide_dec = new SpeexDecoder(NSpeex.BandMode.Wide, true);
        private SpeexEncoder m_wide_enc = new SpeexEncoder(NSpeex.BandMode.Wide);

        public SpeexCodec()
        {
            this.m_wide_enc.Quality = 5;
            this.m_narrow_enc.Quality = 5;
            this.m_ultrawide_enc.Quality = 5;
        }

        public short[] Decode(byte[] data, BandMode mode)
        {
            return this.SpeexDecode(data, mode);
        }

        public byte[] Encode(short[] data, BandMode mode)
        {
            return this.SpeexEncode(data, mode);
        }

        public int GetSampleSize(int recordingFrequency)
        {
            switch (recordingFrequency)
            {
                case 0x1f40:
                    return 320;

                case 0x3e80:
                    return 640;

                case 0x7d00:
                    return 0x500;
            }
            return 320;
        }

        private short[] SpeexDecode(byte[] input, BandMode mode)
        {
            SpeexDecoder decoder = null;
            int length = 320;
            switch (mode)
            {
                case BandMode.Narrow:
                    decoder = this.m_narrow_dec;
                    length = 320;
                    break;

                case BandMode.Wide:
                    decoder = this.m_wide_dec;
                    length = 640;
                    break;

                case BandMode.UltraWide:
                    decoder = this.m_ultrawide_dec;
                    length = 0x500;
                    break;
            }
            byte[] @byte = USpeakPoolUtils.GetByte(4);
            Array.Copy(input, @byte, 4);
            int inCount = BitConverter.ToInt32(@byte, 0);
            USpeakPoolUtils.Return(@byte);
            byte[] dst = USpeakPoolUtils.GetByte(input.Length - 4);
            Buffer.BlockCopy(input, 4, dst, 0, input.Length - 4);
            short[] @short = USpeakPoolUtils.GetShort(length);
            decoder.Decode(dst, 0, inCount, @short, 0, false);
            USpeakPoolUtils.Return(dst);
            return @short;
        }

        private byte[] SpeexEncode(short[] input, BandMode mode)
        {
            SpeexEncoder encoder = null;
            int num = 320;
            switch (mode)
            {
                case BandMode.Narrow:
                    encoder = this.m_narrow_enc;
                    num = 320;
                    break;

                case BandMode.Wide:
                    encoder = this.m_wide_enc;
                    num = 640;
                    break;

                case BandMode.UltraWide:
                    encoder = this.m_ultrawide_enc;
                    num = 0x500;
                    break;
            }
            byte[] @byte = USpeakPoolUtils.GetByte(num + 4);
            Array.Copy(BitConverter.GetBytes(encoder.Encode(input, 0, input.Length, @byte, 4, @byte.Length)), @byte, 4);
            return @byte;
        }
    }
}

